package com.google.code.timeeditapplication.view.implementation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.google.code.timeeditapplication.model.implementation.ScheduleItem;

/**
 * @author Sam Odeh
 * @version 0.1
 * @since 2011-10-11
 */
public class CustomView extends LinearLayout {

	private final LinkedList<CustomScheduleObject> drawnObjects = new LinkedList<CustomScheduleObject>();
	private ArrayList<ScheduleItem> scheduleList = new ArrayList<ScheduleItem>();
	private int totalWidth;
	private int totalHeight;
	private boolean dontDraw = true;
	private int textSize = 16;

	/**
	 * Class constructor
	 * 
	 * @param context
	 */
	public CustomView(final Context context) {
		super(context);
	}

	/**
	 * Class constructor
	 * 
	 * @param context
	 * @param attrs
	 */
	public CustomView(final Context context, final AttributeSet attrs) {
		super(context, attrs);
	}

	/**
	 * Adds a list with schedule items for the current day. If no list has been
	 * added, no schedule will be drawn. When this is called it clears the
	 * previous list.
	 * 
	 * @param list
	 *            list of schedule items
	 * @param ts
	 *            TextSize on the buttons being drawn
	 */
	public void addScheduleList(final ArrayList<ScheduleItem> list, final int ts) {
		this.drawnObjects.clear();
		this.scheduleList.clear();
		this.scheduleList = list;
		this.textSize = ts;
		if (this.scheduleList.size() != 0) {
			this.dontDraw = false;
		}
	}

	/**
	 * @inheritDoc
	 */
	// Gets the width and height from its parent, then "if" a list of
	// "scheduleitems" has been
	// added, it will call drawScheduleObjects();
	// Parent layout can't be absolute layout, will result in error
	@Override
	protected void onMeasure(final int widthMeasureSpec,
			final int heightMeasureSpec) {
		final int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
		final int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
		this.totalWidth = parentWidth;
		this.totalHeight = parentHeight;
		setMeasuredDimension(parentWidth, parentHeight);
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		if (this.dontDraw == false) {
			this.dontDraw = true;
			drawScheduleObjects();
		}
	}

	/*
	 * This is a vertical Linear Layout, which means we add objects from the top
	 * to the bottom.
	 * 
	 * Sets "currentpixelposition" to zero.
	 * 
	 * calls sortScheduleList, which sorts the list so all objects gets in order
	 * based on start time.
	 * 
	 * Loops through the list, taking one schedule object at a time.
	 * 
	 * ---Loop---
	 * 
	 * 1) Gets all properties from the schedule object
	 * 
	 * 2) Calculates pph(pixel per hour), so that for example if something is
	 * being drawn at 10, it's 2 hours from 08(start value), it should then
	 * start to be drawn at 2*pph. pph calculates height.
	 * 
	 * 3)Calculates a schedule objects start position(where the object should be
	 * added), also formats the time, so it's displayed right.
	 * 
	 * 4)Checks if "currentpixelposition" is at the same position as start
	 * position, if not, an empty object will be added at the current position
	 * until it reaches the start position, then a "CustomScheduleItem" will be
	 * created and added.
	 * 
	 * 5)If there are two scheduleItems at the same time, both will be drawn in
	 * an horizontal linear layout.
	 * 
	 * ---Loop---
	 */

	private void drawScheduleObjects() {
		removeAllViews();
		setOrientation(VERTICAL);
		int currentPixelPos = 0;
		Collections.sort(this.scheduleList);
		for (int i = 0; i < this.scheduleList.size(); i++) {
			final ScheduleItem currentScheduleItem = this.scheduleList.get(i);
			final String name = currentScheduleItem.getName();
			final String location = currentScheduleItem.getLocation();
			// adding +1 to compensate for time saving
			final int startHour = currentScheduleItem.getStartHour() + 1;
			final int startMinute = currentScheduleItem.getStartMinute();
			// adding +1 to compensate for time saving
			final int endHour = currentScheduleItem.getEndHour() + 1;
			final int endMinute = currentScheduleItem.getEndMinute();
			final int pph = (this.totalHeight / 9);
			final int height = getScheduleItemheight(startHour, startMinute,
					endHour, endMinute, pph);
			final int width = this.totalWidth;
			final float tempPos = (float) (((((float) startHour - 8) + ((float) startMinute / 60)) * pph) + 0.5);
			final int startPos = (int) tempPos;
			final String timeString = getTimeString(startHour, startMinute,
					endHour, endMinute);

			while (true) {
				if (currentPixelPos >= startPos) {

					if ((i + 1) == this.scheduleList.size()) {
						final CustomScheduleObject cso = new CustomScheduleObject(
								getContext()).createScheduleObject(width,
								height, name, location, timeString,
								this.textSize);
						this.drawnObjects.add(cso);
						this.addView(cso);

					} else if (currentScheduleItem.getStartTime().equals(
							this.scheduleList.get(i + 1).getStartTime())) {
						final LinearLayout linearHorizontal = new LinearLayout(
								getContext());
						linearHorizontal.setOrientation(HORIZONTAL);
						final CustomScheduleObject cso = new CustomScheduleObject(
								getContext()).createScheduleObject((width / 2),
								height, name, location, timeString,
								this.textSize);
						linearHorizontal.addView(cso);
						this.drawnObjects.add(cso);

						final CustomScheduleObject cso2 = new CustomScheduleObject(
								getContext())
								.createScheduleObject(
										(width / 2),
										height,
										this.scheduleList.get(i + 1).getName(),
										this.scheduleList.get(i + 1)
												.getLocation(),
										getTimeString(
												(this.scheduleList.get(i + 1)
														.getStartHour() + 1),
												this.scheduleList.get(i + 1)
														.getStartMinute(),
												(this.scheduleList.get(i + 1)
														.getEndHour() + 1),
												this.scheduleList.get(i + 1)
														.getEndMinute()),
										this.textSize);
						linearHorizontal.addView(cso2);
						this.drawnObjects.add(cso2);
						this.addView(linearHorizontal);
						i++;

					} else {
						final CustomScheduleObject cso = new CustomScheduleObject(
								getContext()).createScheduleObject(width,
								height, name, location, timeString,
								this.textSize);
						this.drawnObjects.add(cso);
						this.addView(cso);
					}
					currentPixelPos = currentPixelPos + (height);
					break;

				} else {
					this.addView(new RelativeLayout(getContext()), width,
							startPos - currentPixelPos);
					currentPixelPos = currentPixelPos
							+ (startPos - currentPixelPos);
				}
			}

		}
		setVisibility(VISIBLE);
		setWillNotDraw(false);
		invalidate();
	}

	/*
	 * Gets start and end time as Integers, returns a String with the format:
	 * 10.00 -- 11.45
	 */
	private String getTimeString(final int startHour, final int startMinute,
			final int endHour, final int endMinute) {
		String sHour = startHour + "";
		String sMinute = startMinute + "";
		String eHour = endHour + "";
		String eMinute = endMinute + "";
		if (sHour.length() == 1) {
			sHour = "0" + sHour;
		}
		if (sMinute.length() == 1) {
			sMinute = sMinute + "0";
		}
		if (eHour.length() == 1) {
			eHour = "0" + eHour;
		}
		if (eMinute.length() == 1) {
			eMinute = eMinute + "0";
		}
		final String timeString = sHour + "." + sMinute + " -- " + eHour + "."
				+ eMinute;
		return timeString;
	}

	/**
	 * @inheritDoc
	 */

	@Override
	public void onDraw(final Canvas canvas) {
		super.onDraw(canvas);
	}

	// Return the height of a schedule object, requires pph(pixelperhour).
	private int getScheduleItemheight(final int startHour,
			final int startMinute, final int endHour, final int endMinute,
			final int pph) {
		final float hour = ((float) endHour - (float) startHour)
				+ (((float) endMinute - (float) startMinute) / 60);
		final float height = (hour * pph) + (float) 0.5;

		return (int) height;
		// adding 0,5 to round off
	}
}
